package com.net.xpay.common.service.impl.admin.rbac;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.net.xpay.common.domain.admin.rbac.Menu;
import com.net.xpay.common.domain.admin.rbac.RoleMenu;
import com.net.xpay.common.model.admin.rbac.MenuMeta;
import com.net.xpay.common.model.admin.rbac.MenuModel;
import com.net.xpay.core.enums.MenuLevel;
import com.net.common.exception.BusinessException;
import com.net.common.util.StreamUtil;
import com.net.xpay.common.manager.admin.rbac.MenuManager;
import com.net.xpay.common.manager.admin.rbac.RoleMenuManager;
import com.net.xpay.common.service.admin.rbac.MenuService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 2019/6/4 15:40

 */
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private MenuManager menuManager;

    @Autowired
    private RoleMenuManager roleMenuManager;

    @Override
    public List<Menu> buildMenus(Long adminUserId, Boolean superAdmin) {
        Preconditions.checkArgument(adminUserId != null);
        List<Menu> menus;
        if (Boolean.TRUE.equals(superAdmin)) {
            menus = menuManager.listAll();
        } else {
            menus = menuManager.findByAdminUserId(adminUserId);
        }
        if (CollectionUtils.isEmpty(menus)) {
            return new ArrayList<>();
        }
        menus = StreamUtil.distinct(menus, Menu::getId);
        menus = StreamUtil.filter(menus, menu -> menu.getLevel() < 2);
        return buildTree(menus);
    }

    @Override
    public List<MenuModel> buildMenuModels(List<Menu> menus) {
        List<MenuModel> list = new LinkedList<>();
        if (CollectionUtils.isEmpty(menus)) {
            return list;
        }
        for (Menu menu : menus) {
            if (menu != null) {
                List<Menu> menuList = menu.getChildren();
                MenuModel menuModel = new MenuModel();
                menuModel.setName(menu.getName());
                menuModel.setPath(menu.getPath());
                menuModel.setHidden(menu.getHidden());

                if (menu.getPid().equals(0L)) {
                    //一级目录需要加斜杠，不然访问 会跳转404页面
                    menuModel.setPath("/" + menu.getPath());
                    menuModel.setComponent(Strings.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent());
                } else if (!Strings.isEmpty(menu.getComponent())) {
                    menuModel.setComponent(menu.getComponent());
                }
                menuModel.setMeta(new MenuMeta(menu.getName(), menu.getIcon()));
                if (menuList != null && menuList.size() != 0) {
                    menuModel.setAlwaysShow(true);
                    menuModel.setRedirect("noredirect");
                    menuModel.setChildren(buildMenuModels(menuList));
                    // 处理是一级菜单并且没有子菜单的情况
                } else if (menu.getPid().equals(0L)) {
                    MenuModel menuModel1 = new MenuModel();
                    menuModel1.setMeta(menuModel.getMeta());
                    // 非外链
                    menuModel1.setPath("index");
                    menuModel1.setName(menuModel.getName());
                    menuModel1.setComponent(menuModel.getComponent());
                    menuModel.setName(null);
                    menuModel.setMeta(null);
                    menuModel.setComponent("Layout");
                    List<MenuModel> list1 = new ArrayList<>();
                    list1.add(menuModel1);
                    menuModel.setChildren(list1);
                }
                list.add(menuModel);
            }
        }

        return list;
    }

    @Override
    public List<Map<String, Object>> getMenuTree(List<Menu> menus) {
        if (CollectionUtils.isEmpty(menus)) {
            return new LinkedList<>();
        }
        List<Map<String, Object>> list = new LinkedList<>();
        menus.forEach(menu -> {
                    if (menu != null) {
                        List<Menu> menuList = menuManager.findByPid(menu.getId());
                        Map<String, Object> map = new HashMap<>();
                        map.put("id", menu.getId());
                        map.put("label", menu.getName());
                        if (menuList != null && menuList.size() != 0) {
                            map.put("children", getMenuTree(menuList));
                        }
                        list.add(map);
                    }
                }
        );
        return list;
    }

    @Override
    public List<Menu> listMenu() {
        // 先获取menu表所有的数据
        List<Menu> menus = menuManager.listAll();
        // 对menus进行数据处理,将父子类进行封装
        return menus.stream()
                .filter(menu -> menu.getPid() == 0)
                .peek(menu -> menu.setChildren(getMenuChildren(menus, menu)))
                .sorted(Comparator.comparing(Menu::getSort))
                .collect(Collectors.toList());
    }

    @Override
    public boolean deleteMenu(Long id) {
        Preconditions.checkArgument(id != null);
        // 1. 先查询出数据需要删除的数据
        Menu menu = menuManager.getById(id);
        // 2. 如果数据包含子节点则不允许删除
        List<Menu> menus = menuManager.listAll();
        long count = menus.stream().filter(menu1 -> menu1.getPid().longValue() == menu.getId().longValue()).count();
        if (count > 0) {
            throw new BusinessException("201", "该节点下包含子节点,不允许删除");
        }
        // 3. 判断删除的菜单是否已经被分配了
        RoleMenu roleMenu = roleMenuManager.getRoleMenuByMenuId(id);
        if (roleMenu != null) {
            throw new BusinessException("202", "该菜单(目录,按钮)已被分配,无法删除");
        }
        // 4. 如果没有子节点,则进行删除

        return menuManager.deleteById(id) > 0;
    }

    @Override
    public List<Menu> listNoButtonMenuTree() {
        // 1. 获取所有菜单数据(不包含按钮)
        List<Menu> menus = menuManager.listNoButtonMenu();
        List<Menu> collect = menus.stream()
                .filter(menu -> menu.getPid() == 0)
                .peek(menu -> menu.setChildren(getMenuChildren(menus, menu)))
                .sorted(Comparator.comparing(Menu::getSort))
                .collect(Collectors.toList());
        // 2. 添加顶级菜单
        Menu root = new Menu();
        root.setId(0L);
        root.setName("一级菜单");
        root.setPid(-1L);
        root.setChildren(collect);
        return Lists.newArrayList(root);
    }

    @Override
    public Boolean saveOrUpdateMenu(Menu menu) {
        String prePath = "business/";
        int saveOrUpdate;
        // 预检测
        Preconditions.checkArgument(menu != null);
        Menu menuEntiry = new Menu();
        BeanUtils.copyProperties(menu, menuEntiry);
        // 判断修改menu的类型
        // 1. 按钮
        if (MenuLevel.BUTTON.getValue() == menuEntiry.getLevel()) {
            menuEntiry.setOp(menuEntiry.getPermissions());
            menuEntiry.setPath("");
            menuEntiry.setComponent("");
            menuEntiry.setIcon("");
            menuEntiry.setHidden(0);
        }
        // 菜单
        else if (MenuLevel.MENU.getValue() == menuEntiry.getLevel()) {
            menuEntiry.setIcon("");
            menuEntiry.setComponent(prePath + menuEntiry.getPath());
            menuEntiry.setOp("");
        }
        // 目录
        else {
            menuEntiry.setIcon("system");
            menuEntiry.setPermissions("");
            menuEntiry.setOp("");
            menuEntiry.setHidden(0);
            if(!Strings.isEmpty(menuEntiry.getPath())){
                menuEntiry.setPath(menuEntiry.getPath());
            }else {
                menuEntiry.setPath("");
            }
            menuEntiry.setComponent("");
        }
        if (StringUtils.isEmpty(menuEntiry.getId())) {
            saveOrUpdate = menuManager.save(menuEntiry);
        } else {
            saveOrUpdate = menuManager.update(menuEntiry);
        }
        return saveOrUpdate > 0;
    }


    /**
     * @param menus       : 所有菜单
     * @param currentMenu : 当前菜单
     * @return : Menu
     * @Description:[将当前menu设置children]
     * @author 
     * @date 2020/11/16 10:58
     */
    private List<Menu> getMenuChildren(List<Menu> menus, Menu currentMenu) {
        return menus.stream()
                .filter(menu -> currentMenu.getId().longValue() == menu.getPid().longValue())
                .peek(menu -> menu.setChildren(getMenuChildren(menus, menu)))
                .sorted(Comparator.comparing(Menu::getSort))
                .collect(Collectors.toList());
    }

    private List<Menu> buildTree(List<Menu> menus) {
        List<Menu> trees = new ArrayList<>();

        for (Menu menu : menus) {
            if (menu.getPid() == 0L) {
                trees.add(menu);
            }
            for (Menu it : menus) {
                if (it.getPid().equals(menu.getId())) {
                    if (menu.getChildren() == null) {
                        menu.setChildren(new ArrayList<>());
                    }
                    menu.getChildren().add(it);
                }
            }
        }

        return trees;
    }
}
